Strict

' monkey interface for Scoreoid.net

Import mnet
Import json
Import debug_printer

Class BaaSPlayer

	Field playerParams:String = "username,password,score,difficulty,unique_id,first_name,last_name,email,created,updated,bonus,achievements,best_score,gold,money,kills,lives,time_played,unlocked_levels,unlocked_items,inventory,last_level,current_level,current_time,current_bonus,current_kills,current_achievements,current_gold,current_unlocked_levels,current_unlocked_items,current_lives,xp,energy,boost,latitude,longitude,game_state,platform"
	Field params:StringMap<String> = New StringMap<String>

	Method New()
		Self.Clear()
	End
	
	Method Clear:Int()
'		dp playerParams
		For Local t:String = EachIn playerParams.Split(",")
'			dp "t='" + t + "'"
			Self.SetAttr(t, "")
		Next
		
		Return 0
	End Method
	
	Method SetAttr:Int(a:String, b:String)
'		dp "a=" + a
'		dp "b=" + b
 		If params.Set(a, b) Then
'			dp "set it!"
		Else
'			dp "updated it!"
		EndIf
		Return 0
	End Method

	Method HasAttr:Bool(a:String)
		Return params.Contains(a)
	End
	
	Method GetAttr:String(a:String)
		Return params.Get(a)
	End
End Class

Class BaaSEngine

Private

	Field ScoreoidURL:String
	Field game_id:String
	Field api_key:String
	Field response:String

	Field resultMap:StringMap<String> = New StringMap<String>
	Field resultText:String
	Field success:Bool
	
	Field game:StringMap<String> = New StringMap<String>
	Field pScoresMap:StringMap<String> = New StringMap<String>
	Field player:BaaSPlayer
	Field gScoresMap:StringMap<String> = New StringMap<String>
	
	Field net:Http

	Method httpPost:String(URL:String, params:String)
		Local res:String = net.Post(URL, params)
		Return res
	End

Public

	Method New()
		net = New Http
		player = New BaaSPlayer
		'no default for gameID and APIKey- you MUST provide those
		game_id = ""
		api_key = ""
		
		ScoreoidURL = "https://www.scoreoid.com/"
		response = "json"
		
	End

	Method setURL:Void(newURL:String)
		ScoreoidURL = newURL
	End
	
	Method setGameID:Void(newGameID:String)
		game_id = newGameID
	End

	Method setAPIKey:Void(newAPIKey:String)
		api_key = newAPIKey
	End

	Method setResponseType:Void(newResp:String)
		response = newResp
	End

	Method POST:String(apiCall:String, param:String = "")
		Local URL:String = ScoreoidURL '+ "api/" + apiCall
		#If TARGET="html5" Then
			Local params:String = "action=curl_request&method=" + apiCall + "&response=" + response
			Local skipCheck:Bool = True
		#Else
			Local params:String = "action=curl_request&method=" + apiCall + "&game_id=" + game_id + "&api_key=" + api_key + "&response=" + response
			Local skipCheck:Bool = False
		#End
		Local res:String = ""

		If api_key.Length() > 0 Or skipCheck Then
			If param.Length() > 0 Then
				params += "&" + param
			EndIf
'			dp "params is '" + params + "'"
			res = httpPost(URL, params)
		Else
			#If TARGET="html5" Then
				res = "[{~qerror~q:~qBaaSEngine Problem!~q}]"
			#Else
				res = "[{~qerror~q:~qBaaSEngine NOT INITIALIZED!~q}]"
			#End
		EndIf
		
'		dp "In POST(): URL: '" + URL + "~nparams: '" + params + "'"
		
		Return res
	End
	
	Function add_param:String(towhat:String, pname:String, what:String)
		If what.Length() > 0 Then
			If towhat.Length() > 0 Then
				towhat += "&"
			EndIf
			towhat += pname + "=" + what
		EndIf
		Return towhat
	End
	
	'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
	''''''''' Scoreoid API Interface ''''''''''''''''''''''''''''''
	'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

	' GAME, PLAYER, and SCORE sections:
		
	'''''''''''''''''''''''''''''''''''''''''''''''''''
	'''''''''''''''''''''''''''''''''''''GAME API''''''
	'''''''''''''''''''''''''''''''''''''''''''''''''''

	Method getGame:Bool()
	
		resultText = POST("getGame")
		success = (resultText.Length()) > 0 And ( Not resultText.Contains("{~qerror~q:"))

		If success Then

			resultText = "{" + resultText[2 .. - 1] + "}"
			Local data:JSONDataItem = JSONData.ReadJSON(resultText)
		    Local jsonObject:JSONObject = JSONObject(data)
			Local jobj:JSONObject
			
			If jsonObject <> Null Then ' if contacted server and retrieved data...
			
				jobj = JSONObject(jsonObject.GetItem("Game"))
				
				game.Clear()
	
'				For Local a:String = EachIn jobj.Names()
'				    Local da:String = jobj.GetItem(a)
'				    game.Set(a, da)
'				End
				
			EndIf
		
		Else
			
			resultText = "Error: " + resultText
			
		EndIf
		
		Return success
	End
	
	Method getGameField:Bool(gfield:String)
		Local params:String = ""
		
		params = add_param(params, "field", gfield)
		
		resultText = POST("getGameField", params)
		success = Not resultText.Contains("{~qerror~q:")
		
		Return success
	End

	Method getPlayers:Bool(order_by:String = "", order:String = "", limit:String = "", start_date:String = "", end_date:String = "", platform:String = "")
		Local params:String = ""
		
		params = add_param(params, "order_by", order_by)
		params = add_param(params, "order", order)
		params = add_param(params, "limit", limit)
		params = add_param(params, "start_date", start_date)
		params = add_param(params, "end_date", end_date)
		params = add_param(params, "platform", platform)
		
		resultText = POST("getPlayers", params)
		success = Not resultText.Contains("{~qerror~q:")
		
		Return success
	End
	
	Method getGameAverage:Bool(gfield:String, start_date:String = "", end_date:String = "", platform:String = "")
		Local params:String = ""
	
		params = add_param(params, "field", gfield)
		params = add_param(params, "start_date", start_date)
		params = add_param(params, "end_date", end_date)
		params = add_param(params, "platform", platform)
		
		resultText = POST("getGameAverage", params)
		success = Not resultText.Contains("{~qerror~q:")
		
		Return success
	End
	
	Method getGameTop:Bool(gfield:String, start_date:String = "", end_date:String = "", platform:String = "")
		Local params:String = ""
		
		params = add_param(params, "field", gfield)
		params = add_param(params, "start_date", start_date)
		params = add_param(params, "end_date", end_date)
		params = add_param(params, "platform", platform)

		resultText = POST("getGameTop", params)
		success = Not resultText.Contains("{~qerror~q:")
		
		Return success
	End
	
	Method getGameLowest:Bool(gfield:String, start_date:String = "", end_date:String = "", platform:String = "")
		Local params:String = ""
		
		params = add_param(params, "field", gfield)
		params = add_param(params, "start_date", start_date)
		params = add_param(params, "end_date", end_date)
		params = add_param(params, "platform", platform)
		
		resultText = POST("getGameLowest", params)
		success = Not resultText.Contains("{~qerror~q:")
		
		Return success
	End

	Method getGameTotal:Bool(gfield:String, start_date:String = "", end_date:String = "", platform:String = "")
		Local params:String = ""
		
		params = add_param(params, "field", gfield)
		params = add_param(params, "start_date", start_date)
		params = add_param(params, "end_date", end_date)
		params = add_param(params, "platform", platform)
		
		resultText = POST("getGameTotal", params)
		success = Not resultText.Contains("{~qerror~q:")
		
		Return success
	End
	
	Method getNotification:Bool()
		resultText = POST("getNotification")
		success = Not resultText.Contains("{~qerror~q:")
		
		Return success
	End

	Method getResultText:String()
		Return resultText
	End
	'''''''''''''''''''''''''''''''''''''''''''''''''''
	''''''''''''''''''''''''''''''''''''SCORE API''''''
	'''''''''''''''''''''''''''''''''''''''''''''''''''

	Method createScore:Bool(score:String, username:String, platform:String = "", unique_id:String = "", difficulty:String = "")
		Local params:String = ""
		
		params = add_param(params, "score", score)
		params = add_param(params, "username", username)
		params = add_param(params, "platform", platform)
		params = add_param(params, "unique_id", unique_id)
		params = add_param(params, "difficulty", difficulty)
		
		resultText = POST("createScore", params)
		success = Not resultText.Contains("{~qerror~q:")
		
		Return success
	End

	Method countScores:Bool(start_date:String = "", end_date:String = "", platform:String = "", difficulty:String = "")
		Local params:String = ""
		
		params = add_param(params, "start_date", start_date)
		params = add_param(params, "end_date", end_date)
		params = add_param(params, "platform", platform)
		params = add_param(params, "difficulty", difficulty)
		
		resultText = POST("countScores", params)
		success = Not resultText.Contains("{~qerror~q:")
		
		Return success
	End

	Method countBestScores:Bool(start_date:String = "", end_date:String = "", platform:String = "", difficulty:String = "")
		Local params:String = ""
		
		params = add_param(params, "start_date", start_date)
		params = add_param(params, "end_date", end_date)
		params = add_param(params, "platform", platform)
		params = add_param(params, "difficulty", difficulty)
		
		resultText = POST("countBestScores", params)
		success = Not resultText.Contains("{~qerror~q:")
		
		Return success
	End

	Method getScores:Bool(order_by:String = "", order:String = "", limit:String = "", start_date:String = "", end_date:String = "", platform:String = "", difficulty:String = "")
		Local params:String = ""
		
		params = add_param(params, "order_by", order_by)
		params = add_param(params, "order", order)
		params = add_param(params, "limit", limit)
		params = add_param(params, "start_date", start_date)
		params = add_param(params, "end_date", end_date)
		params = add_param(params, "platform", platform)
		params = add_param(params, "difficulty", difficulty)
		
		resultText = POST("getScores", params)
		success = Not resultText.Contains("{~qerror~q:")
		
		Return success
	End

	Method getBestScores:Bool(order_by:String = "", order:String = "", limit:String = "", start_date:String = "", end_date:String = "", platform:String = "", difficulty:String = "")
		Local params:String = ""
		
		params = add_param(params, "order_by", order_by)
		params = add_param(params, "order", order)
		params = add_param(params, "limit", limit)
		params = add_param(params, "start_date", start_date)
		params = add_param(params, "end_date", end_date)
		params = add_param(params, "platform", platform)
		params = add_param(params, "difficulty", difficulty)
		
		resultText = POST("getBestScores", params)
		success = Not resultText.Contains("{~qerror~q:")

		resultMap.Clear()
		
		If success Then
			Local uText:String = "{" + resultText[2 .. - 1] + "}"
			Local data:JSONDataItem = JSONData.ReadJSON(uText)
		    Local jsonObject:JSONObject = JSONObject(data)

			resultText = ""
			
			' for each score result, add to resultText
'			For jobj:JSONObject = EachIn jsonObject
'				resultText += jobj.GetItem("Score").GetItem("score") + " " + jobj.GetItem("Player").GetItem("username") + "~n"
				resultText += JSONObject(jsonObject.GetItem("Score")).GetItem("score") + " " + JSONObject(jsonObject.GetItem("Player")).GetItem("username") + "~n"
'			Next
		EndIf

		Return success
	End

	Method getAverageScore:Bool(start_date:String = "", end_date:String = "", platform:String = "", difficulty:String = "")
		Local params:String = ""
		
		params = add_param(params, "start_date", start_date)
		params = add_param(params, "end_date", end_date)
		params = add_param(params, "platform", platform)
		params = add_param(params, "difficulty", difficulty)
		
		resultText = POST("getAverageScore", params)
		success = Not resultText.Contains("{~qerror~q:")
		
		Return success
	End

	'''''''''''''''''''''''''''''''''''''''''''''''''''
	'''''''''''''''''''''''''''''''''''PLAYER API''''''
	'''''''''''''''''''''''''''''''''''''''''''''''''''

	Method createPlayer:Bool(username:String, xparams:String = "")
		Local params:String = ""
		
		params = add_param(params, "username", username)
		
		If xparams.Length() > 0 Then
			params += xparams
		EndIf
		
		resultText = POST("createPlayer", params)
		success = Not resultText.Contains("{~qerror~q:")
		
		Return success
	End

	Method editPlayer:Bool(username:String, xparams:String = "")
		Local params:String = ""
		
		params = add_param(params, "username", username)
		
		If xparams.Length() > 0 Then
			params += xparams
		EndIf
		
		resultText = POST("editPlayer", params)
		success = Not resultText.Contains("{~qerror~q:")
		
		Return success
	End
	
	Method deletePlayer:Bool(username:String)
		Local params:String = ""
		
		params = add_param(params, "username", username)
		
		resultText = POST("deletePlayer", params)
		success = Not resultText.Contains("{~qerror~q:")
		
		Return success
	End

	Method getPlayer:Bool(username:String = "", password:String = "", id:String = "", email:String = "")
	
		Local params:String = ""
		
		params = add_param(params, "id", id)
		params = add_param(params, "username", username)
		params = add_param(params, "password", password)
		params = add_param(params, "email", email)

'		dp "in getPlayer(): params = '" + params + "'"
		resultText = POST("getPlayer", params)
'		success = Not resultText.Contains("{~qerror~q:")
		success = (resultText.Length() > 0) And Not resultText.Contains("{~qerror~q:")
		
		player.Clear()
		
		If success Then
			resultText = "{" + resultText[2 .. - 1] + "}"
			Local data:JSONDataItem = JSONData.ReadJSON(resultText)
		    Local jsonObject:JSONObject = JSONObject(data)
			Local jobj:JSONObject = JSONObject(jsonObject.GetItem("Player"))
			For Local a:String = EachIn jobj.Names()
			    Local da:String = jobj.GetItem(a)
			    player.SetAttr(a, da)
			End
		EndIf
		
		Return success
		
	End

	Method getPlayerField:Bool(username:String, gfield:String)
'	Method getPlayerField:Bool(username:String, gfield:String, pullFromCache:Bool = False)
		Local params:String = ""

		' this could be faster if the data is already available
		' for now, always call the Scoreoid server for player field info
'		If pullFromCache Then
'			params = player.Get(gfield)
'			If params.Length() > 0 Then
'				Return params
'			EndIf
'		EndIf
		
		params = add_param(params, "username", username)
		params = add_param(params, "field", gfield)
		
		resultText = POST("getPlayerField", params)
'		Print "resultText = '" + resultText + "'"

		success = (resultText.Length() > 0) And Not resultText.Contains("{~qerror~q:")
		
		If success Then

'			resultText = "{" + resultText[2 .. - 1] + "}"
'			Print "resultText = '" + resultText + "'"
			Local data:JSONDataItem = JSONData.ReadJSON(resultText)
		    Local jsonObject:JSONObject = JSONObject(data)
			Local jobj:String = jsonObject.GetItem(gfield)
		    player.SetAttr(gfield, jobj)
			
		EndIf
		
		Return success
	End

	Method updatePlayerField:Bool(username:String, gfield:String, gvalue:String)
		Local params:String = ""
		
		params = add_param(params, "username", username)
		params = add_param(params, "field", gfield)
		params = add_param(params, "value", gvalue)
		
		resultText = POST("updatePlayerField", params)
		success = Not resultText.Contains("{~qerror~q:")
		
		Return success
	End

	Method getPlayerScores:Bool(username:String, start_date:String = "", end_date:String = "", difficulty:String = "")
		Local params:String = ""
		
		params = add_param(params, "username", username)
		params = add_param(params, "start_date", start_date)
		params = add_param(params, "end_date", end_date)
		params = add_param(params, "difficulty", difficulty)
		params = add_param(params, "limit", "999999")
		resultText = POST("getPlayerScores", params)

'		dp resultText
		
		success = Not resultText.Contains("{~qerror~q:")

		If success Then
			' put the scores data in the scores object
			pScoresMap.Clear()
			pScoresMap.Set(difficulty, "0") ' just so we don't get NaN if there are no scores for this player yet
			
			' we've received an array from scoreoid
			Local jdi:JSONDataItem = JSONData.ReadJSON(resultText)
			Local jda:JSONArray = JSONArray(jdi)
			
			For Local sa:JSONDataItem = EachIn jda
				Local so:JSONObject = JSONObject(sa)
				Local score:JSONObject = JSONObject(so.GetItem("Score"))

				Local level:String = score.GetItem("difficulty")
				Local iScore:String = score.GetItem("score")
'				Local iRank:String = score.GetItem("rank")
'				Print "level: " + level + ", score: " + iScore + ", Rank: " + iRank
'				dp "level: " + level + ", score: " + iScore
				
				Local cScore:String = pScoresMap.Get(level)

				If cScore.Length() > 0 Then
					If Int(iScore) > Int(cScore) Then
						pScoresMap.Set(level, iScore)
					Else
						' need to delete this particular score from Scoreoid
						' unless you are tracking scores over time...
					EndIf
				Else
					pScoresMap.Set(level, iScore)
				EndIf
				
'				For Local jsonName:String = EachIn score.Names()
'					Print jsonName + " = " + score.GetItem(jsonName)
'				Next
			Next
		EndIf
		
		Return success
	End

	Method countPlayers:Bool(start_date:String = "", end_date:String = "", platform:String = "")
		Local params:String = ""
		
		params = add_param(params, "start_date", start_date)
		params = add_param(params, "end_date", end_date)
		params = add_param(params, "platform", platform)
		
		resultText = POST("countPlayers", params)
		success = Not resultText.Contains("{~qerror~q:")
		
		Return success
	End

	Method getPlayerData:Bool(username:String, gfield:String, use_cache:Bool = True)
		Local params:String = ""
		Local pfield:String = "playerData_" + gfield
		
		' this could be faster if the data is already available
		' for now, always call the Scoreoid server for player field info
'		If pullFromCache Then
'			params = player.Get(gfield)
'			If params.Length() > 0 Then
'				Return params
'			EndIf
'		EndIf

		If player.HasAttr(pfield) And use_cache Then
			'return it from cache
'			dp "Getting " + gfield + " (" + pfield + ") from cache."
			resultText = player.GetAttr(pfield)
			success = True
		Else
			' get it
'			dp "Getting " + gfield + " (" + pfield + ") from Scoreoid."
			params = add_param(params, "username", username)
			params = add_param(params, "key", gfield)
			
			resultText = POST("getPlayerData", params)
	'		Print "resultText = '" + resultText + "'"
	
			success = (resultText.Length() > 0) And Not resultText.Contains("{~qerror~q:")
			
			If success Then
	
	'			resultText = "{" + resultText[2 .. - 1] + "}"
	'			Print "resultText = '" + resultText + "'"
				Local data:JSONDataItem = JSONData.ReadJSON(resultText)
			    Local jsonObject:JSONObject = JSONObject(data)
				Local jobj:String = jsonObject.GetItem(gfield)
			    player.SetAttr("playerData_" + gfield, jobj)
				
			EndIf
		EndIf
		
		Return success
	End

	'''''''''''''''''''''''''''''''''''''''''''''''''''
	'''''''''''''''''''''''''''''HELPER FUNCTIONS''''''
	'''''''''''''''''''''''''''''''''''''''''''''''''''
	
	Method GetPlayerScore:Int(level:String = "")
'		Print "Getting score for " + level
'		Print "pScoresMap.Get(level):" + pScoresMap.Get(level)
		Return Int(pScoresMap.Get(level) + 0)
	End

	Method UpdateHighScore:Void(level:String, iScore:String)
		pScoresMap.Set(level, iScore)
	End
	
	Method login:Bool(username:String = "", password:String = "", id:String = "", email:String = "")
		If getPlayer(username, password, id, email) Then
'			dp "Getting player scores..."
			Return True
		Else
			Return False
		EndIf
	End
	
	Method Ping:Bool()
		Return getGame()
	End
	
	Method getGameName:String()
		Return game_id
	End
End
